using System;
using System.Collections.Generic;
using System.Data;
using System.Reflection;
using System.Text;

namespace QQZiFramework
{
    /// <summary>
    /// 查询参数
    /// </summary>
    public class QueryParam
    {
        /// <summary>
        /// 查询Tree结构,要过滤的ParentCode
        /// </summary>
        public object TreeParent { get; set; }
        public string permission;
        private string _queryField;
        public string queryField { set { _queryField = value; } }
        /// <summary>
        /// 实体类型，用在不传entityName，直接使用该类
        /// </summary>
        public Type entityType { get; set; }
        private string _entityName;
        /// <summary>
        /// 实体名，entityType为空时使用，根据初始化DbContext的format来定位全名，如果传入的是全名，则直接用
        /// </summary>
        public string entityName
        {
            set
            {
                _entityName = value;
                entityType = Type.GetType(_entityName);
                if (entityType == null) throw new Exception(_entityName + "类型找不到!");
            }
        }
        // private string _whereJson;
        /// <summary>
        /// 要查询的字段
        /// </summary>
        public List<QueryField> QueryFields;
        // /// <summary>
        // /// 查询条件Json字符串，用在ClientWhere为空的情况
        // /// </summary>
        // public string whereJson
        // {
        //     get { return _whereJson; }
        //     set
        //     {
        //         _whereJson = value;
        //         if (ClientWhere != null) throw new ClientException("ClientWhere已经有值，不允许再给whereJson赋值！");
        //         if (value != null) ClientWhere = Newtonsoft.Json.JsonConvert.DeserializeObject<Dictionary<string, IWhereItem>>(_whereJson);
        //     }
        // }
        



        /// <summary>
        /// 排序
        /// </summary>
        public String orderBy;

        ///单个查询严格模式，默认=QueryParam.StrictModel
        public bool? StrictModel;

        public List<OrderField> OrderFields;

        DBContext context;

        /// <summary>
        /// 查询条件生成器
        /// </summary>
        BaseQueryParamConditionBuilder defaultConditionBuilder;
         

        internal static QueryParam CreateFromContext(DBContext context)
        {
            QueryParam queryParam = new QueryParam();
            queryParam.context = context;
            return queryParam;
        }

        /// <summary>
        /// 查询条件字典
        /// </summary>
        public Dictionary<string, IWhereItem> ClientWhere=new Dictionary<string, IWhereItem>();
       

        
        public QueryParam(){
            
        }

        public QueryParamConditionBuilder<IDBEntity> From(Type entityType)
        {
            this.entityType = entityType;
            var build = new QueryParamConditionBuilder<IDBEntity>();
            build.SetContext(this.context, this);
            defaultConditionBuilder = build;
            return build;
        }
        public QueryParamConditionBuilder<T> From<T>() where T : IDBEntity
        {
            this.entityType = typeof(T);
            var build =new QueryParamConditionBuilder<T>();
            build.SetContext(this.context, this);
            defaultConditionBuilder = build;
            return build;
        }

        public QueryParam Select(String queryField)
        {
            this.queryField = queryField;
            return this;
        }

        public QueryParam Permission(String permission)
        {
            this.permission = permission;
            return this;
        }

        public QueryParam OrderBy(String orderBy)
        {
            this.orderBy = orderBy;
            return this;
        }


        /// <summary>
        /// 分页
        /// </summary>
        public Pagger Page { get; set; }
        private void initQueryField()
        {
            if (QueryFields == null)
            {
                QueryFields = new List<QueryField>();
                //解析查询列                
                if (string.IsNullOrEmpty(_queryField) || _queryField == "*")//不传查询内容，或者为*
                {
                    ParseStarColumn();
                }
                else
                {
                    foreach (string fieldName in _queryField.Split(','))
                    {

                        if (fieldName == "*")
                        {
                            ParseStarColumn();
                        }
                        else
                        {

                            QueryField qf = new QueryField();
                            CustomerProperty cusPro = LoaderInfo.GetCustomerProperty(fieldName);
                            if (cusPro == null) { qf.CustomValue = fieldName; }//自定义字段，不在实体属性中，比如convert()之类
                            else { qf.Attr = cusPro.Attr; qf.Info = cusPro.Info; }
                            QueryFields.Add(qf);
                        }
                    }
                }
            }

            if (QueryFields != null && QueryFields.Count == 0) throw new ClientException("查询列为空");
        }
        /// <summary>
        /// 初始化Type，外部访问都用entityType
        /// </summary>
        /// <param name="format"></param>
        public void InitParam(string format, DBContext dbContext)
        {
            context = dbContext;
            if (defaultConditionBuilder == null)
            {
                //兼容不是用ConditionBuilder，直接使用ClientWhere的
                var build = new QueryParamConditionBuilder<IDBEntity>();               
                defaultConditionBuilder = build;
            }           
            defaultConditionBuilder.SetContext(context,this);
            if (entityType == null) throw new ArgumentNullException("entityType");
            initQueryField();            
            //是否有标记删除，有则带入where
            var defaultGroup = defaultConditionBuilder.GetDefaultGroup();
            if (LoaderInfo.MarkDeleteCusPro != null && defaultGroup.FindItem(LoaderInfo.MarkDeleteCusPro.Info.Name) == null)
            {
                var markeDeleteOrGroup = new QueryParamConditionGroup() { Conjunction = QueryParamConditionGroup.ConditionGroupConjunction.or };
                markeDeleteOrGroup.Items.Add(new QueryParamConditionItem(LoaderInfo.MarkDeleteCusPro.Info.Name, new WhereItem_NotEq(LoaderInfo.MarkDeleteCusPro.Attr.MarkDeleteValue[1])));
                markeDeleteOrGroup.Items.Add(new QueryParamConditionItem(LoaderInfo.MarkDeleteCusPro.Info.Name, new WhereItem_Custom("${field} is null", null)));
                defaultGroup.Groups.Add(markeDeleteOrGroup);
            }
            //order by
            OrderFields = new List<OrderField>();
            if (!string.IsNullOrEmpty(orderBy))
            {
                foreach (string orderItem in orderBy.Split(','))
                {
                    OrderField qf = new OrderField();
                    string[] orderItemArr = orderItem.Trim().Split(' ');
                    string fieldName = orderItemArr[0];
                    CustomerProperty cusPro = LoaderInfo.GetCustomerProperty(fieldName);
                    if (cusPro == null) { qf.CustomValue = fieldName; }//自定义字段，不在实体属性中，比如convert()之类
                    else { qf.Attr = cusPro.Attr; qf.Info = cusPro.Info; }
                    if (orderItemArr.Length > 1) qf.Orientation = orderItemArr[orderItemArr.Length - 1];
                    OrderFields.Add(qf);
                }
            }
        }

        /// <summary>
        /// 解析*号列为全部
        /// </summary>
        private void ParseStarColumn()
        {
            foreach (CustomerProperty cusPro in LoaderInfo.CustomerPropertys)
            {
                bool isDbfield;
                if (cusPro.Attr != null) isDbfield = cusPro.Attr.IsDBField(context);
                else isDbfield = true;
                if (isDbfield && cusPro.Info.PropertyType.Namespace == "System")
                {
                    bool isExists = false;
                    int pos = -1;
                    if (_queryField != null && _queryField.Length > 2) pos = (',' + _queryField + ',').IndexOf(',' + cusPro.Info.Name + ',');
                    if (pos > -1)
                    {
                        isExists = true;
                    }
                    if (!isExists) QueryFields.Add(new QueryField() { Attr = cusPro.Attr, Info = cusPro.Info });
                }
            }
        }
        /// <summary>
        /// 将动态类设置为查询条件
        /// </summary>
        /// <param name="obj"></param>
        public void SetWhere(object obj)
        {
            // ClientWhere = new Dictionary<string, IWhereItem>();
            foreach (PropertyInfo pi in obj.GetType().GetProperties())
            {
                object val = pi.GetValue(obj, null);
                AddWhere(pi.Name, val);
            }
        }

        /// <summary>
        /// 添加条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam AddWhere(string fieldName, object val)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var arr = fieldName.Split("__");
            IWhereItem whereItem = null;
            string key = arr.Length > 1 ? arr[1].ToLower() : (val == null ? "isnull" : null);

            switch (key)
            {
                case "in":
                    {
                        if (val == null) return this;
                        object[] values;
                        if (val is string) values = ((string)val).Split(",");
                        else values = (object[])val;
                        whereItem = new WhereItem_In(values);
                        break;
                    }
                case "notin":
                    {
                        if (val == null) return this;
                        object[] values;
                        if (val is string) values = ((string)val).Split(",");
                        else values = (object[])val;
                        whereItem = new WhereItem_NotIn(values);
                        break;
                    }
                case "like":
                    {
                        if (val == null) return this;
                        whereItem = new WhereItem_Like(val.ToString());
                        break;
                    }
                case "between":
                    {
                        if (val == null) return this;
                        string[] values;
                        if (val is string) values = ((string)val).Split("|");
                        else values = (string[])val;
                        string start = values[0];
                        string end = null;
                        if (values.Length > 1) end = values[1];
                        whereItem = new WhereItem_Between(start, end);
                        break;
                    }
                case "noteq":
                    {
                        if (val == null) return this;
                        whereItem = new WhereItem_NotEq(val);
                        break;
                    }
                case "notnull":
                    {
                        whereItem = new WhereItem_Custom("${field} is not null", null);
                        break;
                    }
                case "isnull":
                    {

                        whereItem = new WhereItem_Custom("${field} is null", null);
                        break;
                    }
                case "custom":
                    {
                        if (val == null) return this;
                        whereItem = new WhereItem_Custom { Value = (WhereItem_Custom.WhereItem_Custom_Value)val };
                        break;
                    }
                case "gt":
                    {
                        if (val == null) return this;
                        if (arr.Length > 1) fieldName = arr[0];
                        WhereGt(fieldName, val);
                        break;
                    }
                case "lt":
                    {
                        if (val == null) return this;
                        if (arr.Length > 1) fieldName = arr[0];
                        WhereLt(fieldName, val);
                        break;
                    }
                default:
                    {
                        if (val == null) return this;
                        whereItem = new WhereItem_Eq(val.ToString());
                        break;
                    }

            }

            if (whereItem != null)
            {
                if (arr.Length > 1) fieldName = arr[0];
                if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
                else ClientWhere[fieldName] = whereItem;
            }
            return this;
        }

        /// <summary>
        /// 添加=条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam WhereEq(string fieldName, object value)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_Eq(value);
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }
        /// <summary>
        /// 添加=条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam WhereNotEq(string fieldName, object value)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_NotEq(value);
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }

        /// <summary>
        /// 添加in条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam WhereIn(string fieldName, object[] values)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_In(values);
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }


        /// <summary>
        /// 添加Between条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam WhereBetween(string fieldName, object start, object end)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_Between(start, end);
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }

        /// <summary>
        /// 添加大于条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam WhereGt(string fieldName, object value)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_Custom("${field} > {0}", value);
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }

        /// <summary>
        /// 添加大于条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam WhereLt(string fieldName, object value)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_Custom("${field} < {0}", value);
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }

        /// <summary>
        /// 添加isnull条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam WhereIsNull(string fieldName)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_Custom("${field} is null", null);
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }

        /// <summary>
        /// 添加is not null条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam WhereNotNull(string fieldName)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_Custom("${field} is not null", null);
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }



        /// <summary>
        /// 添加like条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam WhereLike(string fieldName, string values)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_Like(values);
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }

        /// <summary>
        /// 添加自定义条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam WhereCustom(string fieldName, string exp, string[] values)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_Custom(exp, values);
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }

        /// <summary>
        /// 添加自定义条件，在初始化Param但未开始查询的时候可调用
        /// </summary>
        /// <param name="fieldName"></param>
        /// <param name="value">值，多个使用|隔开，对应permission.Fields {0}|{1}...</param>
        public QueryParam GrouBy(string fieldName)
        {
            //if (ClientWhere == null) ClientWhere = new Dictionary<string, IWhereItem>();
            var whereItem = new WhereItem_GroupBy();
            if (!ClientWhere.ContainsKey(fieldName)) ClientWhere.Add(fieldName, whereItem);
            else ClientWhere[fieldName] = whereItem;
            return this;
        }

        /// <summary>
        /// 添加自定义列查询
        /// </summary>
        /// <param name="customerQ">查询内容，比如in (...)，或者distinct 1</param>
        /// <param name="index">要插入的位置索引</param>
        public void AddCustomerQuery(string customerQ, int index)
        {
            initQueryField();
            QueryFields.Insert(index, new QueryField() { CustomValue = customerQ, CustomValueStrictModel = false });
        }


        internal string GenWhereSql(QueryEntityInstance queryInstance, DBTableAttribute tableAttr,  out IDbDataParameter[] parameters)
        {
             if(ClientWhere!=null){
                foreach(var clientWhereItem in ClientWhere){
                    defaultConditionBuilder.GetDefaultGroup().Items.Add(new QueryParamConditionItem(clientWhereItem.Key,clientWhereItem.Value));
                }
            }
            return  defaultConditionBuilder.GenGroupWhereSql(queryInstance,out parameters);  
        }


        EntityLoaderInfo m_loaderInfo;

        /// <summary>
        /// 实体解析
        /// </summary>

        public EntityLoaderInfo LoaderInfo
        {
            get
            {
                if (m_loaderInfo == null)
                {
                    m_loaderInfo = EntityLoaderInfo.GetEntityLoaderInfo(entityType);
                }
                return m_loaderInfo;
            }
        }

        /// <summary>
        /// 不传StrictModel的话，默认是否严格模式
        /// </summary>
        /// <value></value>
        public static bool DefaultStrictModel { get; set; }

    }

    public class QueryField : CustomerProperty
    {
        public QueryField() { CustomValueStrictModel = true; }

        /// <summary>
        /// 自定义列查询内容，比如in (...)
        /// </summary>
        public string CustomValue { get; set; }

        /// <summary>
        /// 自定义列是否受严格模式影响
        /// </summary>
        public bool CustomValueStrictModel { get; set; }
    }

    public class OrderField : QueryField
    {
        /// <summary>
        /// 排序方向asc or desc
        /// </summary>
        public string Orientation { get; set; }
    }
}